package core.validate;

import java.util.*;

public class ArrayRule extends Rule<ArrayRule> {
    public ArrayRule(String key) {
        super(key);
        actions.add(holder -> {
            List<Object> value;
            if(holder.getValue() instanceof String val){
                // 逗号分割
                String[] array = val.split(",");
                holder.setValue(Arrays.asList(array));
            }
            holder.setStatus(holder.getValue() instanceof List).setMessage(getMessage());
        });
    }
    protected ArrayRule inst() {
        return this;
    }

    public ArrayRule distinct(String message){
        actions.add(holder -> {
            List<Object> value = holder.getValue();
            Set<Object> setVal = new HashSet<>(value);
            holder.setStatus(value.size() == setVal.size())
                    .setMessage(getMessage(message));
        });

       return this;
    }

    public ArrayRule hasKey(){
        return this;
    }

    public ArrayRule hasValue(Object target, String message){
        actions.add(holder -> {
           List<Object> value = holder.getValue();
           holder.setStatus(value.contains(target))
                   .setMessage(getMessage(message));
        });
        return this;
    }

    public ArrayRule length(int len, String message){
        actions.add(holder -> {
            List<Object> value = holder.getValue();
            holder.setStatus(value.size() == len).setMessage(getMessage(message));
        });
        return this;
    }

    public ArrayRule min(int min, String message){
        actions.add(holder -> {
            List<Object> value = holder.getValue();
            holder.setStatus(value.size() >= min).setMessage(getMessage(message));
        });
        return this;
    }
    public ArrayRule max(int max, String message){
        actions.add(holder -> {
            List<Object> value = holder.getValue();
            holder.setStatus(value.size() <= max).setMessage(getMessage(message));
        });
        return this;
    }

    public ArrayRule item(Rule<?> rule){
        actions.add(holder -> {
            Object value = holder.getValue();
            boolean status = false;
            StringBuilder message = new StringBuilder();
            if(value instanceof List<?> nv){
                Map<String, Object> origin = new HashMap<>();
                List<String> keys = new ArrayList<>();
                for(int index = 0; index < nv.size(); index++){
                    String key = String.valueOf(index);
                    origin.put(key, nv.get(index));
                    keys.add(key);
                }
                Holder itemHolder = new Holder(origin);
                status = validateItem(itemHolder, rule, keys);

                if(status) {
                    Map<String, Object> data = itemHolder.getValues();
                    List<Object> values = new ArrayList<>();
                    for (String key : keys) {
                        values.add(data.get(key));
                    }
                    holder.setValue(values).setMessage(getMessage());
                }else {
                    Map<String, String> messages = itemHolder.getMessages();
                    for (Map.Entry<String, String> entry : messages.entrySet()) {
                        if (!message.isEmpty()) {
                            message.append(", ");
                        }
                        message.append("第").append(entry.getKey()).append("项：").append(entry.getValue());
                    }
                    holder.setMessage(getMessage(message.toString()));
                }
            }
            holder.setStatus(status);
        });
        return this;
    }

    private boolean validateItem(Holder holder, Rule<?> rule, List<String> keys){
        for(String key: keys) {
            holder.setHandle(key);
            if(rule.hasPreCheck()){
                Object preValue = rule.doPreCheck(holder.getValue());
                holder.setValue(preValue);
                holder.setOrigin(holder.getHandle(), preValue);
            }
            if(holder.isEmpty()){
                holder.setValue(null);
                continue;
            }
            for(RuleAction action: rule.actions){
                action.apply(holder);
                if(!holder.getStatus()){
                    break;
                }
            }
        }
        return holder.getGlobalStatus();
    }
}
